﻿using System.Runtime.CompilerServices;
using Unity.Properties;
using UnityEngine;
using static Unity.Mathematics.math;
namespace CollisionLib
{
    using Unity.Mathematics;
    using Primitives;

    public static partial class coll
    {
        public static bool RayCast(sphere sphere, ray ray, float rayDist, float rayRadius)
        {
            var rayEnd = ray.origin + ray.direction * rayDist;
            var closestPointOnRay = ClosestPointOnLineSegment(ray.origin, rayEnd, sphere.center);
            var dist = distance(closestPointOnRay, sphere.center);
            return dist < rayRadius + sphere.radius;
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static void ProjectPointToLineSegment(float3 lineStart, float3 lineEnd, float3 point, out float t)
        {
            var v = lineStart - lineEnd;
            t = dot(point - lineStart, v) / dot(v, v);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static float3 closest(lineseg lineseg, float3 point)
        {
            return ClosestPointOnLineSegment(lineseg.start, lineseg.end, point);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static float3 ClosestPointOnLineSegment(float3 lineStart, float3 lineEnd, float3 point)
        {
            var v = lineEnd - lineStart;
            var t = dot(point - lineStart, v) / dot(v, v);
            t = max(t, 0.0f);
            t = min(t, 1.0f);
            return lineStart + v * t;
        }

        public static float DistanceToSegment(float3 lineStart, float3 lineEnd, float3 point, out float3 closest)
        {
            closest = ClosestPointOnLineSegment(lineStart, lineEnd, point);
            return distance(point, closest);
        }

        public static bool OverlapCapsuleAABB(capsule capsule, box AABB)
        {
            var closestOnCapsule = ClosestPointOnLineSegment(capsule.p1, capsule.p2, AABB.center);

            float sqDist;
            float3 closestInBox;
            CalculateClosestPointInBox(closestOnCapsule, AABB, out closestInBox, out sqDist);
            return math.sqrt(sqDist) < capsule.radius;
        }

        public static bool OverlapCapsuleBox(capsule capsule, box box)
        {
            // Transform capsule into box space
            var rayCapsule = capsule;
            var invBoxRot = math.inverse(box.rotation);
            var invBoxPos = -math.mul(invBoxRot, box.center);
            rayCapsule = primlib.transform(rayCapsule, invBoxPos, invBoxRot);

            var primLocalSpace = box;
            primLocalSpace.center = float3.zero;
            primLocalSpace.rotation = Quaternion.identity;

            var hit = coll.OverlapCapsuleAABB(rayCapsule, primLocalSpace);
            return hit;
        }

        public static void CalculateClosestPointInBox(float3 point, box AABB, out float3 outPoint, out float outSqrDistance)
        {
            // compute coordinates of point in box coordinate system
            float3 closest = point - AABB.center;

            float3 halfSize = AABB.size * 0.5f;
            // project test point onto box
            float fSqrDistance = 0.0f;
            float fDelta;

            for (int i = 0; i < 3; i++)
            {
                if (closest[i] < -halfSize[i])
                {
                    fDelta = closest[i] + halfSize[i];
                    fSqrDistance += fDelta * fDelta;
                    closest[i] = -halfSize[i];
                }
                else if (closest[i] > halfSize[i])
                {
                    fDelta = closest[i] - halfSize[i];
                    fSqrDistance += fDelta * fDelta;
                    closest[i] = halfSize[i];
                }
            }

            // Inside
            if (fSqrDistance == 0.0F)
            {
                outPoint = point;
                outSqrDistance = 0.0F;
            }
            // Outside
            else
            {
                outPoint = closest + AABB.center;
                outSqrDistance = fSqrDistance;
            }
        }
    }
}
